
// const myPromiseAll = (promises) => {
//   if (!Array.isArray(promises)) throw new Error('参数不合法')
//   return new Promise((resolve, reject) => {
//     const results = []
//     promises.forEach((promise, index) => {
//       Promise.resolve(promise)
//         .then(value => {
//           results[index] = value
//           if (results.length === promises.length) resolve(results)
//         })
//         .catch(reject)
//     })
//   })
// }


// console.log(myPromiseAll([Promise.resolve]))


// 防抖函数
// function dou (func, wait) {
//   if (!(func instanceof Function)) throw new Error('参数为非函数')
//   let timeoutId = null
//   return function (...args) {
//     if (timeoutId) clearTimeout(timeoutId)
//     timeoutId = setTimeout(() => {
//       func.apply(this, args)
//       timeoutId = null
//     }, wait)
//   }
// }



// 立即执行版
// function douImmediate (func, wait, immediate) {
//   let timeoutId = null
//   let count = 0
//   const init = immediate

//   return function (...args) {
//     if (immediate) {
//       immediate = false
//       func.apply(this, args)
//     } else {
//       count++
//     }
//     if (timeoutId) clearTimeout(timeoutId)
//     timeoutId = setTimeout(() => {
//       if (count) func.apply(this, args)
//       timeoutId = null
//       immediate = init
//       count = 0
//     }, wait)
//   }
// }

// function debounce(func, wait, immediate) {
//   let timeoutId = null
//   return function(...args) {
//     if (immediate && !timeoutId) {
//       // immediate = true 并且当前没有定时器，表示本次是第一次调用立即执行
//       func.apply(this, args);
//     }
//     if (timeoutId) clearTimeout(timeoutId)
//     timeoutId = setTimeout(() => {
//       func.apply(this, args);
//       timeoutId = null // 执行完最后一次之后清除id
//     }, wait)
//   }
// }



// function jie (func, wait) {
//   let start = 0
//   return function (...args) {
//     const now = Date.now()
//     if (now - start > wait) {
//       func.apply(this, args)
//       start = now
//     }
//   }
// }

// function intv (a) {
//   console.log(a)
// }

// const newIntv = douImmediate (intv, 1000, true)

// document.addEventListener('click', () => {
//   newIntv('aa')
// })

// function cloneDeep(source, isProto = false) {
//   var target;
//   switch (true) {
//     case source instanceof Function:
//       var arr = source
//         .toString()
//         .replace(/\n/g, "")
//         .match(/^.*?\((.*?)\)\s*\{(.*)\}/)
//         .slice(1);
//       target = new Function(...arr);
//       break;
//     case source instanceof HTMLElement:
//       target = source.cloneNode(true);
//       break;
//     case source.buffer && source.buffer instanceof ArrayBuffer:
//     case source instanceof Date:
//     case source instanceof RegExp:
//     case source instanceof Set:
//     case source instanceof Map:
//       target = new source.constructor(source);
//       break;
//     case isProto:
//       target = {};
//       break;
//     default:
//       target = new source.constructor();
//   }
//   var names = Reflect.ownKeys(source);
//   for (var i = 0; i < names.length; i++) {
//     var desc = Object.getOwnPropertyDescriptor(source, names[i]);
//     if (
//       (desc.value && typeof desc.value === "object") ||
//       typeof desc.value === "function"
//     ) {
//       if (names[i] === "prototype") {
//         Object.defineProperty(desc.value, "constructor", {
//           value: target,
//         });
//       }
//       if (names[i] === "constructor") {
//         continue;
//       }
//       Object.defineProperty(target, names[i], {
//         enumerable: desc.enumerable,
//         configurable: desc.configurable,
//         writable: desc.writable,
//         value:
//           names[i] === "prototype"
//             ? cloneDeep(desc.value, true)
//             : cloneDeep(desc.value),
//       });
//     } else {
//       Object.defineProperty(target, names[i], desc);
//     }
//   }
//   return target;
// }
// console.log(cloneDeep({}))

// const add = (e) => {console.log(e)}
// add.apply(this, [1])

// function cloneDeep (source, isPrototype = false) {
//   const typeofType = typeof source
//   if (typeofType !== 'object') return source

//   let target

//   switch (true) {
//     case source instanceof HTMLElement:
//       target = source.cloneNode(true)
//       break
//     case source instanceof Map:
//     case source instanceof Set:
//     case source instanceof Date:
//     case source instanceof RegExp:
//     case source.buffer && source.buffer instanceof ArrayBuffer:
//       target = new source.constructor(source)
//       break
//     case isPrototype:
//       target = {}
//       break
//     default:
//       target = new source.constructor()
//   }
//   return target
// }

// // console.log(cloneDeep(true))
// console.log(cloneDeep(function () {

// }))

// 数组转树形
// const items = [
//   { id: 1, title: 'home', parentId: null },
//   { id: 2, title: 'about', parentId: null },
//   { id: 3, title: 'team', parentId: 2 },
//   { id: 4, title: 'contact', parentId: null },
//   { id: 5, title: 'team1', parentId: 3 },
//   { id: 6, title: 'team2', parentId: 3 }
// ];
// function toTree (arr) {
//   return arr.reduce((res, item) => {
//     const parent = arr.find(v => v.id === item.parentId)
//     if (parent) {
//       parent.children ? parent.children.push(item) : parent.children = [item]
//     } else {
//       res.push(item)
//     }
//     return res
//   }, [])
// }
// console.log(toTree(items))

// 数组扁平化

// let arr = [1,2,[3,4,[5,[6]]]]
// // 递归版
// function flat (arr) {
//   return arr.reduce((res, item) => {
//     return res.concat(Array.isArray(item) ? flat(item) : [item])
//   }, [])
// }
// function flat (arr, num) {
//   if (num === 0) return arr
//   return arr.reduce((res, item) => {
//     return res.concat(Array.isArray(item) ? flat(item, num - 1) : [item])
//   }, [])
// }
// // while循环版
// function flat (arr) {
//   while (arr.some(v => Array.isArray(v))) {
//     arr = [].concat(...arr)
//   }
//   return arr
// }
// function flat (arr, num) {
//   while (num && arr.some(v => Array.isArray(v))) {
//     arr = [].concat(...arr)
//     num--
//   }
//   return arr
// }


// console.log(flat(arr, 1))

// // 合并两个有序数组
// const arr1 = [1, 3, 5];
// const arr2 = [2, 4, 6, 7, 8];

// function concat (arr1, arr2) {
//   const [short, long] = [arr1, arr2].sort((a, b) => a.length - b.length)
//   return short.reduce((res, item, index) => {
//     return res.concat([item, long[index]].sort())
//   }, []).concat(long.slice(short.length, long.length))
// }

// console.log(concat(arr1, arr2))

// console.log([1].concat(1, 2, [1, 3]))

// 格式化query数据

// function query (url) {
//   const search = url.split('?')[1]
//   console.log(search)
//   return search.split('&').reduce((res, item) => {
//     let [key, val] = item.split('=')
//     key = decodeURIComponent(key)
//     val = decodeURIComponent(val)
//     if (!isNaN(val)) val = +val
//     if (res[key]) {
//       Array.isArray(res[key]) ? res[key].push(val) : res[key] = [res[key], val]
//     } else {
//       res[key] = val
//     }
//     return res
//   }, {})
// }

// console.log(query('https://baidu.com?a=1&a=2&b=3&c=NaN'))  // { a: [1, 2], b: 3 }

// // 版本号排序
// function versionSort (arr) {
//   return arr.sort((a, b) => {
//     const verA = a.split('.')
//     const verB = b.split('.')
//     const maxLength = Math.max(verA.length, verB.length)
//     for (let i = 0; i < maxLength; i++) {
//       let itemA = parseInt(verA[i]) || 0
//       let itemB = parseInt(verB[i]) || 0
//       if (itemA !== itemB) return itemA - itemB
//     }
//     return 0
//   })
// }

// console.log(versionSort(["1.5", "1.45", "5.1", "1.2.3", "2.6"]));

// 发布订阅者模式
//   class Event {
//     list = new Map()
//     on (name, callback) {
//       this.list.has(name)
//         ? this.list.set(name, [...this.list.get(name), callback])
//         : this.list.set(name, [callback])
//     }
//     off (name, callback) {
//       if (!this.list.has(name)) return
//       const callbacks = this.list.get(name).filter(v => v !== callback)
//       callbacks.length
//         ? this.list.set(name, callbacks)
//         : this.list.delete(name)
//     }
//     emit (name, ...args) {
//       if (!this.list.has(name)) return
//       this.list.get(name).forEach((fn) => {
//         fn(...args)
//         if (fn._isOnce) this.off(name, fn)
//       })
//     }
//     once (name, callback) {
//       const wrapper = (...args) => {
//         callback(...args)
//       }
//       wrapper._isOnce = true
//       this.on(name, wrapper)
//     }
//   }

// const e = new Event()
// const y = new Set()
// y.add(1)
// y.add(2)
// y.add(3)
// console.log(y)

// e.on('click', (e) => console.log(e))
// e.on('click', () => console.log(111))
// e.emit('click', '你好')

// e.once('on', (e) => console.log(e))

// e.emit('on', 11)
// e.emit('on', 11)
// e.emit('on', 11)
// e.emit('on', 11)
// e.emit('on', 11)

// 查找出现次数最多的字符
// let s = 'bcabcaaabcdaaesssssssssssg'
// function getMax (str) {
//   return str.split('').reduce((res, item) => {
//     res[item]
//       ? res[item]++
//       : res[item] = 1
//     if (res.max.count < res[item])
//       res.max = {val: item, count: res[item]}
//     return res
//   }, {max: {val: '', count: 0}})
// }


// console.log(getMax(s).max.count)


// function add (...args1) {
//   let rest = [].concat(args1)
//   return function fn (...args2) {
//     rest = rest.concat(args2)
//     return args2.length
//       ? fn
//       : rest.reduce((prev, next) => prev + next)
//   }
// }
// console.log(add(1)(2)(3)(1, 2, 3)())
// 1, 111, 222, 333
// 千分符
// function th (num) {
//   const [int, float] = num.toString().split('.')
//   const reg = /\B(?=(\d{3})+(?!\d))/g
//   return int.replace(reg, ',') + (float ? '.' + float : '')
// }

// console.log(th(1234234.12389712322))
// console.log(th(1234234423))


// const arr = [1, 2, 2, 3, 4, 4, 5]

// function uniqueArray (arr) {
//   return Array.from(new Set(arr))
//   return arr.filter((item, index) => arr.indexOf(item) === index)
// }

// console.log(uniqueArray(arr))


// var str = "get-element-by-id"

// function fn (str) {
//   return str.replace(/-\w/g, ($0) => $0.slice(1).toUpperCase())
// }

// console.log(fn(str))



// const tree = [
//   {
//     value: 1,
//     children: [
//       {
//         value: 2,
//         children: [
//           {
//             value: 3,
//             children: []
//           },
//           {
//             value: 4,
//             children: []
//           }
//         ]
//       },
//       {
//         value: 5,
//         children: [
//           {
//             value: 6,
//             children: []
//           },
//           {
//             value: 7,
//             children: []
//           }
//         ]
//       }
//     ]
//   },
//   {
//     value: 8,
//     children: [
//       {
//         value: 9,
//         children: [
//           {
//             value: 10,
//             children: []
//           },
//           {
//             value: 11,
//             children: []
//           }
//         ]
//       },
//       {
//         value: 12,
//         children: [
//           {
//             value: 13,
//             children: []
//           },
//           {
//             value: 14,
//             children: [
//               {
//                 value: 15,
//                 children: []
//               },
//             ]
//           }
//         ]
//       }
//     ]
//   }
// ];

// console.log(tree);

// function treeDeep (tree) {
//   if (!Array.isArray(tree) || !tree) {
//     return 0
//   }
//   if (!tree.length) return 0
//   let deep = 1
//   for (let val of tree) {
//     deep = Math.max(treeDeep(val.children), deep)
//   }
//   return deep + 1
// }

// console.log(treeDeep(tree))

// 并发请求

function delay (time, text) {
  return new Promise((resolve) => {
    resolve(text)
  }).then((res) => {
    setTimeout(() => {
      console.log(res)
    }, time)
  })
}

const test = [
  delay(2000, '第一个'),
  delay(1000, '第二个'),
  delay(3000, '第三个'),
  delay(1000, '第四个'),
  delay(4000, '第五个')
]

concurrentRequests(test, 3)

function concurrentRequests (promises, limit) {
  let curPromise = limit
  const clonePromises = [...promises]

  clonePromises.slice(0, limit)
    .forEach((promise) => {
      run(promise)
    })

  function run (prom) {
    Promise.resolve(prom)
      .then(() => {})
      .catch(e => console.log(e))
      .finally(() => {
        curPromise++
        if (clonePromises[curPromise - 1])
          run(clonePromises[curPromise - 1])
      })
  }
}
